import multer from 'multer';
import sharp from 'sharp';
import path from 'path';
import fs from 'fs/promises';
import { v4 as uuidv4 } from 'uuid';

// 允许的图片格式
const ALLOWED_MIME_TYPES = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp'];
const ALLOWED_EXTENSIONS = /\.(jpg|jpeg|png|gif|webp)$/i;

// 文件大小限制（5MB）
const MAX_FILE_SIZE = 5 * 1024 * 1024;

// 压缩后的目标质量
const COMPRESSION_QUALITY = 80;

/**
 * 配置multer存储策略（使用内存存储，便于后续压缩处理）
 */
const storage = multer.memoryStorage();

/**
 * 文件过滤器 - 只允许图片格式
 */
const fileFilter = (
  req: Express.Request,
  file: Express.Multer.File,
  cb: multer.FileFilterCallback
): void => {
  const isValidMimeType = ALLOWED_MIME_TYPES.includes(file.mimetype);
  const isValidExtension = ALLOWED_EXTENSIONS.test(file.originalname);

  if (isValidMimeType && isValidExtension) {
    cb(null, true);
  } else {
    cb(new Error('只允许上传图片文件（jpg、png、gif、webp）！'));
  }
};

/**
 * 配置multer上传中间件
 */
export const uploadDishImage = multer({
  storage,
  fileFilter,
  limits: {
    fileSize: 10 * 1024 * 1024, // 临时允许10MB上传，后续会压缩
  },
});

/**
 * 压缩图片到目标大小以下
 * @param buffer 原始图片Buffer
 * @param targetSizeBytes 目标文件大小（字节）
 * @returns 压缩后的Buffer
 */
async function compressImageToSize(
  buffer: Buffer,
  targetSizeBytes: number = MAX_FILE_SIZE
): Promise<Buffer> {
  let quality = COMPRESSION_QUALITY;
  let compressed = buffer;

  // 获取图片元数据
  const metadata = await sharp(buffer).metadata();
  const format = metadata.format || 'jpeg';

  // 如果已经小于目标大小，直接返回
  if (buffer.length <= targetSizeBytes) {
    return buffer;
  }

  // 逐步降低质量直到文件小于目标大小
  while (quality > 10 && compressed.length > targetSizeBytes) {
    const sharpInstance = sharp(buffer);

    // 根据格式选择压缩策略
    switch (format) {
      case 'jpeg':
      case 'jpg':
        compressed = await sharpInstance.jpeg({ quality }).toBuffer();
        break;
      case 'png':
        compressed = await sharpInstance.png({ quality }).toBuffer();
        break;
      case 'webp':
        compressed = await sharpInstance.webp({ quality }).toBuffer();
        break;
      case 'gif':
        // GIF 需要特殊处理，转换为 webp 以便压缩
        compressed = await sharpInstance.webp({ quality }).toBuffer();
        break;
      default:
        compressed = await sharpInstance.jpeg({ quality }).toBuffer();
    }

    // 如果压缩后仍然过大，降低质量继续尝试
    if (compressed.length > targetSizeBytes) {
      quality -= 10;
    }
  }

  // 如果质量降到最低仍然过大，尝试缩小尺寸
  if (compressed.length > targetSizeBytes && metadata.width && metadata.height) {
    const scaleFactor = Math.sqrt(targetSizeBytes / compressed.length);
    const newWidth = Math.floor(metadata.width * scaleFactor);
    const newHeight = Math.floor(metadata.height * scaleFactor);

    compressed = await sharp(buffer)
      .resize(newWidth, newHeight, { fit: 'inside' })
      .jpeg({ quality: 70 })
      .toBuffer();
  }

  return compressed;
}

/**
 * 解析项目根目录（兼容源码运行与dist编译后运行）
 */
function getServerRootDir(): string {
  const isDistBuild = __dirname.includes(`${path.sep}dist${path.sep}`);
  return isDistBuild ? path.resolve(__dirname, '..', '..') : path.resolve(__dirname, '..');
}

const SERVER_ROOT_DIR = getServerRootDir();
const UPLOADS_ROOT_DIR = path.join(SERVER_ROOT_DIR, 'uploads');

/**
 * 处理上传的图片文件（压缩并保存）
 * @param file multer上传的文件对象
 * @param subFolder 子文件夹名称（如 'dishes'）
 * @returns 相对路径（如 /uploads/dishes/xxx.jpg）
 */
export async function processUploadedImage(
  file: Express.Multer.File,
  subFolder: string = 'dishes'
): Promise<string> {
  if (!file || !file.buffer) {
    throw new Error('无效的文件对象');
  }

  try {
    // 生成唯一文件名
    const uniqueId = uuidv4();
    const timestamp = Date.now();
    const ext = path.extname(file.originalname).toLowerCase() || '.jpg';
    const filename = `${uniqueId}-${timestamp}${ext}`;

    // 确保上传目录存在
    const uploadDir = path.join(UPLOADS_ROOT_DIR, subFolder);
    await fs.mkdir(uploadDir, { recursive: true });

    // 压缩图片
    const compressedBuffer = await compressImageToSize(file.buffer, MAX_FILE_SIZE);

    // 保存文件
    const filePath = path.join(uploadDir, filename);
    await fs.writeFile(filePath, compressedBuffer);

    // 返回相对路径（前端将基于 API_BASE_URL 拼接完整URL）
    return `/uploads/${subFolder}/${filename}`;
  } catch (error) {
    console.error('图片处理失败:', error);
    throw new Error('图片处理失败，请重试');
  }
}

/**
 * 删除文件
 * @param relativeUrl 相对路径（如 /uploads/dishes/xxx.jpg）
 */
export async function deleteUploadedFile(relativeUrl: string): Promise<void> {
  if (!relativeUrl) return;

  try {
    // 从相对路径提取文件路径
    const normalizedPath = relativeUrl.replace(/^\/+/, '');
    const filePath = path.join(SERVER_ROOT_DIR, normalizedPath);
    await fs.unlink(filePath);
    console.log(`✅ 已删除文件: ${relativeUrl}`);
  } catch (error) {
    // 文件不存在时不报错
    if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
      console.error('删除文件失败:', error);
    }
  }
}

/**
 * 获取完整URL（用于生成响应数据）
 * 注意：前端应该自行基于 API_BASE_URL 拼接，此函数仅供后端测试使用
 * @param relativeUrl 相对路径
 * @returns 完整URL
 */
export function getFullImageUrl(relativeUrl: string): string {
  if (!relativeUrl) return '';
  const baseUrl = process.env.API_BASE_URL || 'http://localhost:3912';
  return `${baseUrl}${relativeUrl}`;
}
